// 15.1 模板实参推导的过程
// 模板实参推导（Template Argument Deduction）是 C++ 编译器根据函数调用的实际参数，自动确定模板参数类型的过程。

// 基本概念
// 当你调用一个函数模板但没有显式指定模板参数时，编译器会尝试从函数调用的实际参数推导出模板参数。例如：
template <typename T>
void f(T param);

f(42); // 编译器推导 T 为 int

// ------------------------------------------------
// 推导的基本过程
// 模板实参推导的过程可以概括为以下步骤：
// 1.模式匹配：编译器将函数调用的实际参数类型与函数模板的参数声明进行模式匹配。
// 2.类型调整：在匹配过程中，编译器会考虑一些类型调整（如引用、const、数组到指针的退化等）。
// 3.确定模板参数：基于匹配结果，确定每个模板参数的具体类型。

// ------------------------------------------------
// 例子：基本类型推导
template <typename T>
void f(T param);

int x = 42;
const int cx = x;
const int &rx = x;

f(x);  // T 被推导为 int，param 类型为 int
f(cx); // T 被推导为 int，param 类型为 int（const 被忽略）
f(rx); // T 被推导为 int，param 类型为 int（引用和 const 被忽略）

// -------------------------------------------------
// 例子：引用参数的推导
template <typename T>
void f(T &param); // 注意这里是引用参数

int x = 42;
const int cx = x;

f(x);  // T 被推导为 int，param 类型为 int&
f(cx); // T 被推导为 const int，param 类型为 const int&

// -------------------------------------------------
// 例子：数组和函数的推导
template <typename T>
void f(T param);

int arr[10];
f(arr); // T 被推导为 int*（数组退化为指针）

void g();
f(g); // T 被推导为 void(*)()（函数退化为函数指针）

// ------------------------------------------------
// 特殊情况：多参数推导
// 当函数模板有多个参数时，每个参数都会参与推导，如果推导结果冲突，会导致编译错误：
template <typename T>
void f(T a, T b); // 两个参数必须是同一类型 T

f(1, 2);   // 正确：T 被推导为 int
f(1, 2.5); // 错误：T 不能同时是 int 和 double

// ------------------------------------------------
// 特殊情况：显式指定部分模板参数
// 可以显式指定部分模板参数，让编译器推导其余参数：
template <typename T, typename U>
void f(T a, U b);

f<int>(1, 2.5); // T 被显式指定为 int，U 被推导为 double

// 总结
// 模板实参推导是编译器根据函数调用的实际参数自动确定模板参数类型的过程。
// 推导过程考虑了类型调整，如引用、const 和类型退化。
// 不同的参数声明方式（值、引用、const 等）会影响推导结果。
// 多参数推导要求推导结果一致，否则会出错。
